
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace HDJ.Framework.Core
{
    /// <summary>表示无限大数的类</summary>
    public struct BigNumber : IComparable<BigNumber>
    {
        /// <summary>一位上存储的数位</summary>
        public static readonly int OneCount = 9;
        /// <summary>
        /// 除法小数最大占位DivisionDecimalPrecision * 4;
        /// </summary>
        public const int DivisionDecimalPrecision = 16;

        /// <summary>进位的数</summary>
        public static readonly long Max = (long)Math.Pow(10, OneCount);

        #region 构造函数

        public BigNumber(double value)
        {
            intPart = null;
            decimalPart = null;
            isPlus = true;
            isInit = true;
            Init(value.ToString());
        }

        public BigNumber(decimal value)
        {
            intPart = null;
            decimalPart = null;
            isPlus = true;
            isInit = true;
            Init(value.ToString());
        }
        public BigNumber(long value)
        {
            intPart = null;
            decimalPart = null;
            isPlus = true;
            isInit = true;
            Init(value.ToString());
        }
        public BigNumber(float value)
        {
            intPart = null;
            decimalPart = null;
            isPlus = true;
            isInit = true;
            Init(value.ToString());
        }
        public BigNumber(int value)
        {
            intPart = null;
            decimalPart = null;
            isPlus = true;
            isInit = true;
            Init(value.ToString());
        }
        /// <summary>
        /// 支持输入数字字符串（"123.456"）或科学计数法("1.45E+15","2.5E-10","3.3E10")
        /// </summary>
        /// <param name="text"></param>
        public BigNumber(string text)
        {
            intPart = null;
            decimalPart = null;
            isPlus = true;
            isInit = true;
            Init(text);
        }
        public BigNumber(BigNumber value)
        {
            isInit = true;
            decimalPart = new List<long>(value.DecimalPart);
            isPlus = value.IsPlus;
            intPart = new List<long>(value.IntPart);
        }
        public BigNumber(List<long> i, List<long> d, bool plus)
        {
            isInit = true;
            intPart = i;
            decimalPart = d;
            isPlus = plus;
        }

        private void Init(string text)
        {

            if (string.IsNullOrEmpty(text))
            {
                text = "0";
            }
            string lowerText = text.ToLower();
            if (!lowerText.Contains("e"))
            {
                intPart = new List<long>();
                decimalPart = new List<long>();
                IsPlus = IdentifyNumber.GetBigNumber(text, intPart, decimalPart);
            }
            else
            {
                string[] parts = lowerText.Split('e');
                string headStr = parts[0];
                string powerStr = parts[1];
                BigNumber headNum = new BigNumber(headStr);
                //Debug.Log("headNum :" + headNum);
                BigNumber powNum = new BigNumber(powerStr);
                //Debug.Log("powNum :" + powNum);
                BigNumber powerResNum = new BigNumber(10).Power(powNum);
                //Debug.Log("powerResNum :" + powerResNum);
                BigNumber res = headNum * powerResNum;
                //Debug.Log("res :" + res);
                intPart = res.intPart;
                decimalPart = res.decimalPart;
                IsPlus = res.IsPlus;
            }

        }
        #endregion
        #region "属性"
        //整数部分与小数部分都是从左到右存储
        List<long> intPart;
        List<long> decimalPart;

        /// <summary>整数部分 </summary>
        public List<long> IntPart
        {
            get
            {
                CheckInit();
                return intPart;
            }
            set
            {
                if (intPart != null)
                {
                    intPart.Clear();
                    intPart.AddRange(value);
                }
                else
                    intPart = new List<long>(value);
                //intPart = value;
            }
        }
        private void CheckInit()
        {
            if (!isInit)
            {
                if (intPart == null || decimalPart == null)
                    this = Zero;
                else
                    isInit = true;

            }
        }
        /// <summary>
        /// 是否初始化，用于泛型默认或反射返回默认值时的错误
        /// </summary>
        private bool isInit;
        /// <summary>整数部分的长度</summary>
        public int IntLength
        {
            get { return IntPart.Count * OneCount; }
        }

        /// <summary>
        /// 小数部分
        /// </summary>
        public List<long> DecimalPart
        {
            get
            {
                CheckInit();
                return decimalPart;
            }
            set
            {
                if (decimalPart != null)
                {
                    decimalPart.Clear();
                    decimalPart.AddRange(value);
                }
                else
                    decimalPart = new List<long>(value);
            }
        }
        /// <summary>小数部分的实际长度</summary>
        public int DecimalLength
        {
            get { return DecimalPart.Count * OneCount; }
        }

        /// <summary>返回0.00001这样的数小数点后、有效数前有几个零</summary>
        internal int GetPrecision(int value)
        {
            if (value == 0)
            {
                BigCalculate.RemoveStartZero(IntPart);
                if (IntPart.Count == 1 && IntPart[0] == 0)
                {
                    if (DecimalPart.Count == 0)
                        return 0;
                    for (int i = 0; i < DecimalPart.Count; i++)
                    {
                        if (DecimalPart[i] != 0)
                            return i;
                    }
                    return DecimalPart.Count;
                }
                return 0;
            }
            else
            {
                if (IntPart.Count == 1 && IntPart[0] == 1)
                {
                    if (DecimalPart.Count == 0)
                        return 0;
                    for (int i = 0; i < DecimalPart.Count; i++)
                    {
                        if (DecimalPart[i] != 0)
                            return i;
                    }
                    return DecimalPart.Count;
                }
                return 0;
            }
        }

        private bool isPlus;
        /// <summary>
        /// 是否是正数
        /// </summary>
        public bool IsPlus
        {
            get
            {
                CheckInit();
                return isPlus;
            }
            set
            {
                isPlus = value;
            }
        }

        /// <summary>
        /// 返回此实例的绝对值
        /// </summary>
        public BigNumber AbsoluteNumber
        {
            get { return new BigNumber(IntPart, DecimalPart, true); }
        }
        /// <summary>
        /// 返回当前值的整数（去除小数）
        /// </summary>
        public BigNumber IntegerNumber
        {
            get
            {
                return new BigNumber(IntPart, new List<long>(), IsPlus);
            }
        }


        /// <summary>大数中的零对象</summary>
        public static BigNumber Zero
        {
            get
            {
                List<long> intlist = new List<long>();
                List<long> decimallist = new List<long>();
                intlist.Add(0);
                return new BigNumber(intlist, decimallist, true);
            }
        }
        public static BigNumber One
        {
            get
            {
                List<long> intlist = new List<long>();
                List<long> decimallist = new List<long>();
                intlist.Add(1);
                return new BigNumber(intlist, decimallist, true);
            }
        }
        /// <summary>
        /// -1
        /// </summary>
        public static BigNumber MinusOne
        {
            get
            {
                List<long> intlist = new List<long>();
                List<long> decimallist = new List<long>();
                intlist.Add(1);
                return new BigNumber(intlist, decimallist, false);
            }
        }
        /// <summary>
        /// 判定是否是0
        /// </summary>
        public bool IsZero
        {
            get
            {
                foreach (int i in IntPart)
                    if (i != 0)
                        return false;
                foreach (int i in DecimalPart)
                    if (i != 0)
                        return false;
                return true;
            }
        }

        public BigNumber Clone()
        {
            return new BigNumber(IntPart, DecimalPart, IsPlus);
        }

        /// <summary>保留小数点后n位</summary>
        public void KeepPrecision(int n)
        {
            if (this.DecimalPart.Count > n)
            {
                this.DecimalPart.RemoveRange(n, DecimalPart.Count - n);
            }
        }
        /// <summary>
        /// 移除小数部分多余的0
        /// </summary>
        public BigNumber RemoveDecimalZero()
        {
            for (int i = DecimalPart.Count - 1; i >= 0; i--)
            {
                long num = DecimalPart[i];
                if (num == 0)
                {
                    DecimalPart.RemoveAt(i);
                }
                else
                {
                    break;
                }
            }
            return this;
        }
        #endregion

        #region "隐式转换"
        public static implicit operator BigNumber(int value)
        {
            return new BigNumber(value);
        }
        public static implicit operator BigNumber(float value)
        {
            return new BigNumber(value);
        }
        public static implicit operator BigNumber(double value)
        {
            return new BigNumber(value);
        }
        //public static implicit operator BigNumber(string value)
        //{
        //    return new BigNumber(value);
        //}
        public static implicit operator BigNumber(decimal value)
        {
            return new BigNumber(value);
        }

        #endregion

        #region "重载运算符"
        public static BigNumber operator +(BigNumber a, BigNumber b)
        {
            BigNumber big = BigCalculate.Add(a, b);
            big.RemoveDecimalZero();
            return big;
        }

        public static BigNumber operator +(int a, BigNumber b)
        {
            return (new BigNumber(a)) + b;
        }
        public static BigNumber operator -(BigNumber a, BigNumber b)
        {
            BigNumber big = BigCalculate.Minus(a, b);
            big.RemoveDecimalZero();
            return big;
        }
        public static BigNumber operator -(BigNumber a)
        {
            BigNumber b = new BigNumber(a);
            b.IsPlus = !a.IsPlus;
            return b;
        }
        public static BigNumber operator *(BigNumber a, BigNumber b)
        {
            BigNumber big = BigCalculate.Multiply(a, b);
            big.RemoveDecimalZero();
            return big;
        }
        public static BigNumber operator *(int a, BigNumber b)
        {
            return (new BigNumber(a.ToString())) * b;
        }
        public static BigNumber operator /(BigNumber a, BigNumber b)
        {
            BigNumber big = BigCalculate.Division(a, b, BigNumber.DivisionDecimalPrecision);
            big.RemoveDecimalZero();
            return big;
        }
        public static bool operator >(BigNumber a, BigNumber b)
        {
            int res = a.CompareTo(b);
            return res == 1;
        }
        public static bool operator <(BigNumber a, BigNumber b)
        {
            int res = a.CompareTo(b);
            return res == -1;
        }
        public static bool operator ==(BigNumber a, BigNumber b)
        {
            int res = a.CompareTo(b);
            return res == 0;
        }
        public static bool operator !=(BigNumber a, BigNumber b)
        {
            int res = a.CompareTo(b);
            return res != 0;
        }
        public static bool operator <=(BigNumber a, BigNumber b)
        {
            int res = a.CompareTo(b);
            return res == -1 || res == 0;
        }
        public static bool operator >=(BigNumber a, BigNumber b)
        {
            int res = a.CompareTo(b);
            return res == 1 || res == 0;
        }
        /// <summary>指定精确的除法</summary>
        public static BigNumber Division(BigNumber dividend, BigNumber divisor, int precision)
        {
            return BigCalculate.Division(dividend, divisor, precision);
        }
        public static BigNumber operator ++(BigNumber a)
        {
            return a + BigNumber.One;
        }

        #endregion

        #region "提供阶乘和幂运算"

        /// <summary>返回正整数的阶乘运算</summary>
        public BigNumber Factorial()
        {
            if (!IsPlus || DecimalPart.Count != 0)
                throw new NumberException("只有正整数才有阶乘运算", 1);

            BigNumber result = BigNumber.One;

            for (BigNumber i = BigNumber.One; i < this; i++)
            {
                result = result * i;
            }
            return result;
        }

        /// <summary>
        /// 计算幂，现在可支持任意合法的幂运算
        /// </summary>
        /// <param name="value"></param>
        /// <param name="isUseFastComputation">是否使用快速计算（精度较低，适用于高幂运算）</param>
        /// <returns></returns>
        public BigNumber Power(BigNumber value,bool isUseFastComputation=false)
        {
            if(!isUseFastComputation)
            return Power(value, BigNumber.DivisionDecimalPrecision);
            else
            {
                return IdentifyNumber.PowDim(this, value).RemoveDecimalZero();
            }

        }

        public BigNumber Power(BigNumber value, int n)
        {
            BigNumber big = DeciamlPowerCalculator.Power(this, value, n);
            big.RemoveDecimalZero();
            return big;
        }

        #endregion

        #region 重载 ToString，ToScientificString
        /// <summary>
        /// 直接转换成字符串表示
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return ToString(false);
        }
        /// <summary>
        /// 直接转换成字符串表示
        /// </summary>
        /// <param name="isRemoveDecimalZero">是否移除末尾的多余的小数0，如：5.200=>5.2,1.000=>1</param>
        /// <param name="decimalNum">保存小数精度（非强制性）当小数位多余（isRemoveDecimalZero=true则先移除0）decimalNum，就自动截取，decimalNum大于0时起作用</param>
        /// <returns></returns>
        public string ToString(bool isRemoveDecimalZero, int decimalNum = -1)
        {
            StringBuilder sb = new StringBuilder();
            //Debug.Log("...>" + intPart);
            foreach (int i in IntPart)
            {
                sb.Append(i.ToString().PadLeft(BigNumber.OneCount, '0'));
            }
            //Debug.Log("...>" + intPart.Count +" r :"+sb);
            if (intPart.Count == 0)
            {
                sb.Append(0);
            }
            if (DecimalPart.Count != 0)
            {
                sb.Append(".");

                foreach (int i in DecimalPart)
                {
                    sb.Append(i.ToString().PadLeft(BigNumber.OneCount, '0'));
                }
            }
            string r = sb.ToString();
            r = r.TrimStart(new char[] { '0' });
            //Debug.Log("0>>>" + r);
            if (isRemoveDecimalZero && r.Contains("."))
            {
                r = r.TrimEnd(new char[] { '0' });
            }
            //Debug.Log("1>>>" + r);
            if (r.Length == 1 && r[0] == '.')
                return "0";
            if (r == string.Empty)
                return "0";
            if (r[0] == '.')
                r = "0" + r;
            if (r[r.Length - 1] == '.')
                r = r.Remove(r.Length - 1);

            if (!IsPlus)
                r = "-" + r;
            //Debug.Log("2>>>" + r);
            if (decimalNum > 0 && r.Contains("."))
            {
                int index = r.IndexOf('.');
                int cutIndex = index + decimalNum;
                if (r.Length > cutIndex + 1)
                    r = r.Remove(cutIndex);
            }
            //Debug.Log("3>>>" + r);
            return r;
        }
        /// <summary>
        /// 转换科学计数法输出
        /// </summary>
        /// <param name="greaterNum">当大于greaterNum，则使用科学计数法表示，否则直接输出原数</param>
        /// <param name="decimalNum">保存小数位精度（非强制性）当小数位多余（已则先移除0）decimalNum，就自动截取，decimalNum大于0时起作用</param>
        /// <returns></returns>
        public string ToScientificString(BigNumber greaterNum, int decimalNum)
        {
            if (this > greaterNum)
            {
                return ToScientificString(decimalNum);
            }
            else
            {
                return ToString(true, decimalNum);
            }
        }
        /// <summary>
        /// 转换科学计数法输出
        /// </summary>
        /// <param name="decimalNum">保存小数位精度（非强制性）当小数位多余（已则先移除0）decimalNum，就自动截取，decimalNum大于0时起作用</param>
        /// <returns></returns>
        public string ToScientificString(int decimalNum)
        {
            int cout = 0;
            int powerNum = 0;
            StringBuilder sb = new StringBuilder();

            //Debug.Log("intPart.Count  :" + intPart.Count);
            bool isIntPartZero = true;

            foreach (var item in IntPart)
            {
                if (item != 0)
                {
                    isIntPartZero = false;
                }
            }
            if (IntPart.Count > 0 && !isIntPartZero)
            {
                long maxNum = IntPart[0];
                string maxNumStr = maxNum.ToString();
             //   int index = maxNumStr.Length;
                powerNum += (IntPart.Count - 1) * OneCount + (maxNumStr.Length - 1) ;


                for (int i = 0; i < IntPart.Count; i++)
                {
                    long num = IntPart[i];
                    string nS = num.ToString().PadLeft(BigNumber.OneCount, '0');
                    int j = 0;
                    if (i == 0)
                    {
                       
                        j = (OneCount - num.ToString().Length);
                       // Debug.Log("ns:" + nS + " num.ToString().Length:" + num.ToString().Length);
                        sb.Append(nS[j]);
                        sb.Append('.');
                        j++;
                    }
                    bool end = false;
                    for (; j < OneCount; j++)
                    {
                        sb.Append(nS[j]);
                        cout++;
                        if (cout >= decimalNum && decimalNum > 0)
                        {
                            end = true;
                            break;
                        }
                    }

                    if (end)
                    {
                        break;
                    }
                }

                if ((cout < decimalNum) && decimalNum > 0 || decimalNum <= 0)
                {
                    for (int i = 0; i < DecimalPart.Count; i++)
                    {
                        long num = DecimalPart[i];
                        string nS = num.ToString().PadLeft(BigNumber.OneCount, '0');
                        int j = 0;
                        bool end = false;
                        for (; j < OneCount; j++)
                        {
                            sb.Append(nS[j]);
                            cout++;
                            if (cout >= decimalNum && decimalNum > 0)
                            {
                                end = true;
                                break;
                            }
                        }

                        if (end)
                        {
                            break;
                        }
                    }
                }

            }
            else
            {

                int dIndex = 0;
                int strIndex = 0;
                for (int i = 0; i < DecimalPart.Count; i++)
                {
                    long num = DecimalPart[i];
                    if (num != 0)
                    {
                        dIndex = i;
                        string nS = num.ToString().PadLeft(BigNumber.OneCount, '0');
                        for (int j = 0; j < nS.Length; j++)
                        {
                            powerNum++;
                            if (nS[j] != '0')
                            {
                                strIndex = j;
                                sb.Append(nS[j]);
                                sb.Append('.');
                                break;
                            }
                        }
                        break;
                    }
                }
                powerNum += dIndex * OneCount;

                for (int i = dIndex; i < DecimalPart.Count; i++)
                {
                    long num = DecimalPart[i];
                    string nS = num.ToString().PadLeft(BigNumber.OneCount, '0');
                    int j = 0;
                    bool end = false;
                    if (i == dIndex)
                    {
                        j = strIndex + 1;
                    }
                    for (; j < nS.Length; j++)
                    {
                        sb.Append(nS[j]);
                        cout++;
                        if (cout >= decimalNum && decimalNum > 0)
                        {
                            end = true;
                            break;
                        }
                    }
                    if (end)
                    {
                        break;
                    }
                }

                powerNum = -powerNum;
            }
            if (sb.Length > 0)
            {
                string removeZero = sb.ToString().TrimEnd('0');
                sb.Clear();
                sb.Append(removeZero);

                if (sb[sb.Length - 1] == '.')
                    sb.Append('0');

                sb.Append('E');
                if (powerNum > 0)
                {
                    sb.Append('+');

                }
                sb.Append(powerNum);
                if (!IsPlus)
                    sb.Insert(0, '-');
            }
            else
            {
                sb.Append('0');
            }

            return sb.ToString();
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        public override bool Equals(object obj)
        {
            if (obj == null || obj.GetType() != typeof(BigNumber))
                return false;
            return this == (BigNumber)obj;
        }
        #endregion

        #region IComparable<BigNumber> 成员

        public int CompareTo(BigNumber other)
        {
            return CompareNumber.Compare(this, other);
        }


        #endregion


        #region 基础数据转换
        /// <summary>
        /// 转化为float，当数据溢出时，返回float的最大或最小值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Try2Float(out float value)
        {
            string numStr = ToString();

            bool res = float.TryParse(numStr, out value);
            if (!res)
            {
                if (this > new BigNumber(float.MaxValue))
                    value = float.MaxValue;
                else
                    value = float.MinValue;
            }
            return res;
        }
        /// <summary>
        /// 转化为float，当数据溢出时，返回float的最大或最小值
        /// </summary>
        /// <returns></returns>
        public float ToFloat()
        {
            float value = 0;
            bool res = Try2Float(out value);
            return value;
        }
        /// <summary>
        /// 转化为Int，当数据溢出时，返回Int的最大或最小值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Try2Int(out int value)
        {
            string numStr = IntegerNumber.ToString(true);

            bool res = int.TryParse(numStr, out value);
            if (!res)
            {
                if (this > new BigNumber(int.MaxValue))
                    value = int.MaxValue;
                else
                    value = int.MinValue;
            }
            return res;
        }
        public int ToInt()
        {
            int value = 0;
            bool res = Try2Int(out value);
            return value;
        }
        public bool Try2Long(out long value)
        {
            string numStr = IntegerNumber.ToString(true);
            bool res = long.TryParse(numStr, out value);
            if (!res)
            {
                if (this > new BigNumber(long.MaxValue))
                    value = long.MaxValue;
                else
                    value = long.MinValue;
            }
            return res;
        }
        public long ToLong()
        {
            long value = 0;
            bool res = Try2Long(out value);
            return value;
        }

        #endregion

    }
}
